package com.nbjtjc.safe.activiti.service;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import com.nbjtjc.safe.activiti.listener.MyExecutionListener;
import com.nbjtjc.safe.activiti.listener.ProcessListener;
import com.nbjtjc.safe.activiti.mapper.ExtActNodeMapper;
import com.nbjtjc.safe.activiti.model.*;
import com.nbjtjc.safe.bean.MyCache;
import com.nbjtjc.safe.bean.Page;
import com.nbjtjc.safe.bean.Result;
import com.nbjtjc.safe.mapper.emg.EmgPlanPublicMapper;
import com.nbjtjc.safe.mapper.sys.SysNoticeMapper;
import com.nbjtjc.safe.mapper.sys.SysNoticeTargetMapper;
import com.nbjtjc.safe.model.emg.EmgPlanPublic;
import com.nbjtjc.safe.service.emg.EmgPlanPublicService;
import com.nbjtjc.safe.util.ActUtils;
import com.nbjtjc.safe.util.MyShiroUtils;
import org.activiti.engine.*;
import org.activiti.engine.history.HistoricProcessInstance;
import org.activiti.engine.history.HistoricTaskInstance;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Comment;
import org.activiti.engine.task.Task;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @auther guqianbin
 * @date 2018/5/21 20:14
 * 应急处置的相关流程的操作类
 **/
@Service
public class EmgFlowService {

    @Autowired
    private RepositoryService repositoryService;
    @Autowired
    private TaskService taskService;
    @Autowired
    IdentityService identityservice;
    @Autowired
    RuntimeService runtimeservice;

    @Autowired
    HistoryService historyService;
    @Autowired
    private ActUtils actUtils;
    @Autowired
    private EmgPlanPublicMapper emgPlanPublicMapper;

    @Autowired
    private EmgPlanPublicService emgPlanPublicService;

    @Autowired
    private ExtActNodeMapper extActNodeMapper;
    @Autowired
    private MyExecutionListener myExecutionListener;

    @Autowired
    private SysNoticeMapper sysNoticeMapper;
    @Autowired
    private SysNoticeTargetMapper sysNoticeTargetMapper;
    @Autowired
    private ProcessListener processListener;
    @Autowired
    private MyCache myCache;
    @Value("${emgPlanPublic.finishValue}")
    private Integer finishValue;

    @Autowired
    private ExtActTaskReassignService extActTaskReassignService;

    /**
     * 获取节点
     * @return
     */
    public List<ExtActNode> getEmgFlowStatus() {
        List<ExtActNode> extActNodes = new ArrayList<>();
        ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().processDefinitionKey("emgFlow1")
                .latestVersion().singleResult();
        if (ObjectUtil.isNull(processDefinition)) {
            return extActNodes;
        }
        ExtActNode extActNode = new ExtActNode();
        extActNode.setProcdefId(processDefinition.getId());
        extActNodes = extActNodeMapper.select(extActNode);
        return extActNodes;
    }


    @Transactional(rollbackFor = Throwable.class)
    public Result startEmgFlow(EmgPlanPublic emgPlanPublic, int applyUserId) throws Exception {
        Result result = new Result();
        result = emgPlanPublicService.add(emgPlanPublic, false);
        if (!result.isSuccess()) {
            return result;
        }
        Map<String, Object> variables = new HashMap<>();
        variables.put("applyUserId", applyUserId);
        variables.put("myExecutionListener", myExecutionListener);
        variables.put("processListener", processListener);
        variables.put("busKey", emgPlanPublic.getId());
        identityservice.setAuthenticatedUserId(MyShiroUtils.getSessionUserId().toString());
        ProcessInstance processInstance = runtimeservice
                .startProcessInstanceByKey("emgFlow1", emgPlanPublic.getId().toString(), variables);
        String processId = processInstance.getId();
        emgPlanPublic.setProcessInstanceId(processId);
        Task task = taskService.createTaskQuery().processInstanceId(processId).singleResult();
        taskService.setOwner(task.getId(), MyShiroUtils.getSessionUserId().toString());
        emgPlanPublic.setTaskId(task.getId());
        emgPlanPublicMapper.updateByPrimaryKeySelective(emgPlanPublic);
        if (ObjectUtil.isNotNull(processInstance)) {
            RunningProcess runningProcess = new RunningProcess();
            runningProcess.setActivityid(processInstance.getActivityId());
            runningProcess.setBusinesskey(processInstance.getBusinessKey());
            runningProcess.setExecutionid(processInstance.getId());
            runningProcess.setProcessInstanceid(processInstance.getProcessInstanceId());
            result.setData(runningProcess);
        } else {
            result.setFalse("无任务");
        }
        return result;
    }


    /**
     * 获取我已经做的应急响应的历史任务
     *
     * @param page
     * @return
     */
    public Result getMyEmgHistoryTask(Page page) {
        Result result = Result.res();
        Map<String, Object> data = new HashMap<>();
        page.countPage(historyService
                .createHistoricTaskInstanceQuery()
                .taskAssignee(MyShiroUtils.getSessionUserId().toString())
                .count());
        List<HistoricTaskInstance> historicTaskInstanceList = historyService
                .createHistoricTaskInstanceQuery()
                .taskAssignee(MyShiroUtils.getSessionUserId() + "")
                .listPage(page.getPageSize() * (page.getPageCurrent() - 1), page.getPageSize());
        List<MyTask> myTaskList = new ArrayList<>();
        if (CollectionUtil.isNotEmpty(historicTaskInstanceList)) {
            historicTaskInstanceList.forEach(historicTaskInstance -> {
                MyTask myTask = new MyTask();
                myTask.setName(historicTaskInstance.getName());
                myTask.setProcessInstanceId(historicTaskInstance.getProcessInstanceId());
                myTask.setCreateTime(historicTaskInstance.getCreateTime());
                myTask.setEndTime(historicTaskInstance.getEndTime());
                myTask.setId(historicTaskInstance.getId());
                myTask.setUserId(historicTaskInstance.getAssignee());
                myTask.setProcessDefId(historicTaskInstance.getProcessDefinitionId());
                myTask.setTaskDefinitionKey(historicTaskInstance.getTaskDefinitionKey());
                List<Comment> comments = taskService.getTaskComments(historicTaskInstance.getId());
                if (CollectionUtil.isNotEmpty(comments)) {
                    myTask.setComment(comments.get(0).getFullMessage());
                }
                if (ObjectUtil.isNotNull(historicTaskInstance.getAssignee())) {
                    myTask.setUserName(myCache.getUserName(historicTaskInstance.getAssignee()));
                }
                myTaskList.add(myTask);
            });
        }
        compareHistoryTask(myTaskList);
        data.put("data", myTaskList);
        data.put("page", page);
        result.setData(data);
        return result;
    }


    /**
     * 获取未执行的应急响应的任务
     *
     * @param page
     * @return
     */
    public Result getUndoEmgTasks(Page page, String taskDefineKey) {
        Result result = Result.res();
        Map<String, Object> data = new HashMap<>();
        List<MyTask> myTaskList = new ArrayList<>();
        ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
                .processDefinitionKey("emgFlow1").latestVersion().singleResult();

        List<Task> taskList = new ArrayList<>();
        if (StringUtils.isNotEmpty(taskDefineKey)) {
            page.countPage(taskService.createTaskQuery()
                    .taskAssignee(MyShiroUtils.getSessionUserId().toString())
                    .taskDefinitionKey(taskDefineKey)
                    .processDefinitionId(processDefinition.getId()).count());
            taskList = taskService.createTaskQuery()
                    .taskAssignee(MyShiroUtils.getSessionUserId().toString())
                    .processDefinitionId(processDefinition.getId())
                    .taskDefinitionKey(taskDefineKey)
                    .listPage(page.getPageSize() * (page.getPageCurrent() - 1), page.getPageSize());
        } else {
            page.countPage(taskService.createTaskQuery()
                    .taskAssignee(MyShiroUtils.getSessionUserId().toString())
                    .processDefinitionId(processDefinition.getId()).count());
            taskList = taskService.createTaskQuery()
                    .taskAssignee(MyShiroUtils.getSessionUserId().toString())
                    .processDefinitionId(processDefinition.getId())
                    .listPage(page.getPageSize() * (page.getPageCurrent() - 1), page.getPageSize());

        }

        if (CollectionUtil.isNotEmpty(taskList)) {
            taskList.forEach(task -> {
                MyTask myTask = new MyTask();
                myTask.setCreateTime(task.getCreateTime());
                myTask.setProcessInstanceId(task.getProcessInstanceId());
                myTask.setName(task.getName());
                myTask.setId(task.getId());
                myTask.setTaskDefinitionKey(task.getTaskDefinitionKey());
                myTask.setExecutionId(task.getExecutionId());
                myTask.setUserId(task.getAssignee());
                myTask.setUserName(myCache.getUserName(task.getAssignee()));
                if (ObjectUtil.isNotNull(task.getAssignee())) {
                    myTask.setUserName(myCache.getUserName(task.getAssignee()));
                }
                myTaskList.add(myTask);
            });
        }
        compareRunningTask(myTaskList);
        data.put("data", myTaskList);
        data.put("page", page);
        result.setData(data);
        return result;
    }

    /**
     * 执行任务
     *
     * @param activitiParams
     * @return
     */
    public Result finishTask(ActivitiParams activitiParams) {
        long start = System.currentTimeMillis();
        Result result = new Result();
        String taskId = activitiParams.getTaskId();
        Map<String, Object> params = activitiParams.getParamsMap();
        Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
        if (params.containsKey("comment")) {
            taskService.addComment(taskId, task.getProcessInstanceId(), params.get("comment").toString());
        }
        if (!params.containsKey("applyUserId")) {
            ProcessInstance processInstance = runtimeservice.createProcessInstanceQuery()
                    .processInstanceId(task.getProcessInstanceId()).singleResult();
            params.put("applyUserId", processInstance.getStartUserId());
        }
        //TODO 发布通知，将sysNotice的状态更新为发布
        taskService.setVariablesLocal(taskId, params);
        taskService.complete(taskId, params);
        checkFinish(task);
        return result;
    }

    public InputStream getFlowImgByInstantId(String processInstanceId) throws Exception {
        if (StringUtils.isEmpty(processInstanceId)) {
            throw new Exception("获取流程图片失败，流程实例不能为空!");
        }
        return actUtils.getDiagram(processInstanceId);
    }


    private RunningProcess processCompare(ProcessInstance processInstance) {
        if (ObjectUtil.isNotNull(processInstance)) {
            RunningProcess runningProcess = new RunningProcess();
            runningProcess.setActivityid(processInstance.getActivityId());
            runningProcess.setBusinesskey(processInstance.getBusinessKey());
            runningProcess.setExecutionid(processInstance.getId());
            runningProcess.setProcessInstanceid(processInstance.getProcessInstanceId());
            return runningProcess;
        } else {
            return null;
        }
    }

    /**
     * 根据任务更新状态
     *
     * @param task
     * @return
     */
    private void checkFinish(Task task) {
        ProcessInstance processInstance = runtimeservice.createProcessInstanceQuery()
                .processInstanceId(task.getProcessInstanceId()).singleResult();
        if (ObjectUtil.isNull(processInstance)) {
            HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery().processInstanceId(task.getProcessInstanceId()).singleResult();
            emgPlanPublicMapper.updateStatus(Integer.parseInt(historicProcessInstance.getBusinessKey()), finishValue);
        }
    }

    /**
     * 更新通知的状态为发布
     *
     * @param task
     */
    private void publicNotice(Task task) {
        ExtActNode extActNode = extActNodeMapper
                .findByProcdefIdAndNodeId(task.getProcessDefinitionId()
                        , task.getTaskDefinitionKey());
        if (extActNode.getPublicNotice()) {
            //TODO 更新通知的状态
        }
    }

    /**
     * 讲扩展节点信息，应急响应的信息装配
     *
     * @param myTaskList
     */
    private void compareRunningTask(List<MyTask> myTaskList) {
        long start = System.currentTimeMillis();
        if (CollectionUtil.isEmpty(myTaskList)) {
            return;
        }
        myTaskList.forEach(myTask -> {
            ProcessInstance processInstance = runtimeservice
                    .createProcessInstanceQuery()
                    .processInstanceId(myTask.getProcessInstanceId())
                    .singleResult();
            System.out.println("-----时间3.1-----------------" + (System.currentTimeMillis() - start));
            ExtActNode extActNode = extActNodeMapper
                    .findByProcdefIdAndNodeId(processInstance.getProcessDefinitionId()
                            , myTask.getTaskDefinitionKey());
            myTask.setExtActNode(extActNode);
            System.out.println("-----时间3.2-----------------" + (System.currentTimeMillis() - start));
            EmgPlanPublic emgPlanPublic = emgPlanPublicMapper.getRunningEmgPlanPublic(Integer.parseInt(processInstance.getBusinessKey()));
            System.out.println("-----时间3.3-----------------" + (System.currentTimeMillis() - start));
            if (ObjectUtil.isNotNull(emgPlanPublic)) {
                emgPlanPublic.setStatus(extActNode.getStatus());
                emgPlanPublic.setSignerUserName(myCache.getUserName(emgPlanPublic.getSignerUserId()));
                emgPlanPublic.setStatusName(extActNode.getName());
                compareNoticeTarget(emgPlanPublic);
                System.out.println("-----时间3.4-----------------" + (System.currentTimeMillis() - start));
                myTask.setEmgPlanPublic(emgPlanPublic);
            }
            ExtActTaskReassign extActTaskReassign =
                    extActTaskReassignService.findLatestReassign(myTask.getId());
            if (ObjectUtil.isNotNull(extActTaskReassign)) {
                myTask.setHasReassign(true);
                myTask.setExtActTaskReassign(extActTaskReassign);
            }
        });
    }

    private void compareHistoryTask(List<MyTask> myTaskList) {
        long start = System.currentTimeMillis();
        if (CollectionUtil.isEmpty(myTaskList)) {
            return;
        }
        myTaskList.forEach(myTask -> {
            HistoricProcessInstance historicProcessInstance = historyService
                    .createHistoricProcessInstanceQuery()
                    .processInstanceId(myTask.getProcessInstanceId())
                    .singleResult();
            ExtActNode extActNode = extActNodeMapper
                    .findByProcdefIdAndNodeId(myTask.getProcessDefId()
                            , myTask.getTaskDefinitionKey());
            myTask.setExtActNode(extActNode);
            EmgPlanPublic emgPlanPublic = emgPlanPublicMapper.getRunningEmgPlanPublic(Integer.parseInt(historicProcessInstance.getBusinessKey()));
            if (ObjectUtil.isNotNull(emgPlanPublic)) {
                emgPlanPublic.setStatus(extActNode.getStatus());
                emgPlanPublic.setSignerUserName(myCache.getUserName(emgPlanPublic.getSignerUserId()));
                emgPlanPublic.setStatusName(extActNode.getName());
                compareNoticeTarget(emgPlanPublic);
                myTask.setEmgPlanPublic(emgPlanPublic);
            }
        });
    }

    private void compareNoticeTarget(EmgPlanPublic emgPlanPublic) {
        Integer maxSysNoticeId = sysNoticeMapper
                .findLatestSysNoticeIdByPlanPublicId(emgPlanPublic.getId());
        if (ObjectUtil.isNotNull(maxSysNoticeId)) {
            List<Integer> noticeUserIds = sysNoticeTargetMapper.findUserIdsByNoticeId(maxSysNoticeId);
            emgPlanPublic.setNoticeUserIds(noticeUserIds);
        }
    }
}
